//
//  IFlyIVWRecordService.m
//  AIKITDemo
//
//  Created by xyzhang on 2023/3/14.
//

#import "IFlyIVWRecordService.h"

#import "IFlyIVWConfig.h"
#import "IVWEngine.h"

#import "IFlyDebugLog.h"
#import "IFlyAudioRecorder.h"
#import "IFlyAudioSession.h"


//音频数据最大计数值
#define MAX_AUDIOQUEUE_COUNT_IVW 100

@interface IFlyIVWRecordService ()<IFlyAudioRecorderDelegate, IFlyWakeupEngineDelegate>
{
    int                                 _error;
    BOOL                                _isNeedExit;//线程是否需要退出，有需要退出的标记
    NSMutableDictionary                 *_queue;    //存储音频数据
    NSUInteger                          _audioCount;    //音频数据序号
    BOOL                                _isInc;       //音频序号是否已进位
    NSUInteger                          _index;     //当前写入的音频序号

    BOOL                                _isWait;
    int                                 _netTimeout;//最长等待时间
    NSDate                              *_startDate;//开始时间
    NSDate                              *_stopDate;//结束时间
}

@property (nonatomic, strong) IVWEngine *ivwEngine;

@property (nonatomic, weak) id<IFlyVoiceWakeupDelegate> delegate;

@property (nonatomic, strong) IFlyAudioRecorder *ivwRecorder;

@property (nonatomic, weak) IFlyIVWConfig *config;

@end


@implementation IFlyIVWRecordService

- (instancetype)initWithDelegate:(id<IFlyVoiceWakeupDelegate>)delegate withConfig:(IFlyIVWConfig *)config {
    
    if (self = [super init]) {
        _delegate = delegate;
        _config = config;
        _state = IVWInit;
        
        _ivwEngine = [[IVWEngine alloc] init];
        [_ivwEngine setConfig:config];
        [_ivwEngine setDelegate:self];
        
        _isNeedExit = NO;
        _queue = [[NSMutableDictionary alloc] init];
        _audioCount = 0;
        _isInc = NO;
        _index = 0;
        
        _ivwRecorder = [IFlyAudioRecorder sharedInstance];
        _ivwRecorder.delegate = self;
    }
    
    return self;
}

- (BOOL)stopRecord {
    
    [IFlyDebugLog showLog:@"%s,[IN] state=%d", __func__, _state];
    
    if (_state == IVWRecording ) {
        //停止录音
        [_ivwRecorder stop];
        
        //写入尾数据
        [self writeEndData];
        
        //等待识别结果
        [self setState:IVWWakeuping];
    }
    else if (_state != IVWWakeuping) { //处理：当还没有完成sessionbegin时，用户停止录音，此时需要取消operation
        
        [IFlyDebugLog showLog:@"state=%d, isExecuting=%d", _state, self.isExecuting];
        
        //若当前线程在未执行状态之前cancel，将直接从线程队列移除并且不会进入main方法，以致不会回调onCompleted
        if (_state == IVWInit && self.isExecuting == NO) {
            if ([_delegate respondsToSelector:@selector(onCompletedWithErrorCode:)]){
                [_delegate onCompletedWithErrorCode:_error];
            }
        }
        
        [IFlyDebugLog showLog:@"IFlyIVWService stopRecord, IVWInit"];
        
        [self cancel];
    }
    
    [IFlyDebugLog showLog:@"%s[OUT]",__func__];
    return YES;
}

#pragma mark - private

- (void)main {
    
    [IFlyDebugLog showLog:@"%s[IN],self=%d",__func__, self];
   
    //外部已经取消
    if (self.isCancelled) {
        [IFlyDebugLog showLog:@"%s[OUT],no record.",__func__];
        goto EXIT;
    }
    
    //启动录音，并发出录音开始回调
    BOOL startRet = [self startRecord];
    if (!startRet) {
        [IFlyDebugLog showLog:@"%s record is failed,[OUT],startRet=%d",__func__,startRet];
        _error = 20006;
        goto EXIT;
    }
    
    //录音启动后收到取消消息
    if (self.isCancelled) {
        //终止录音
        [_ivwRecorder stop];
        
        if ([_delegate respondsToSelector:@selector(onEndOfSpeech)]) {
            [_delegate onEndOfSpeech];
        }
        
        goto EXIT;
    }
    
    [self startIVW];
    
    //用户还未说话，已经收到stopAndWait的消息
    if (IVWWakeuping == _state) {
        _isNeedExit = YES;
    }
    
    while (_state != IVWEnd && _error == 0 && !_isNeedExit) {
        //取消唤醒
        if (self.isCancelled) {
            if (_state == IVWRecording) {
                //停止录音
                [_ivwRecorder stop];
                
                //发送录音结束回调
                if ([_delegate respondsToSelector:@selector(onEndOfSpeech)]) {
                    [_delegate onEndOfSpeech];
                }
                
                [self setState:IVWCanceling];
            }
            
            break;
        }
        
        switch (_state) {
            case IVWRecording: {
                [self writeAudioData];
            }
                break;
            case IVWWakeuping: {
                _isNeedExit = YES;
            }
                break;
            default:
                break;
        }
        
        [NSThread sleepForTimeInterval:0.01];
    }
    [IFlyDebugLog showLog:@"while end,self=%d",self];
    
    //确保录音已经关闭
    if (_state == IVWRecording) {
        [_ivwRecorder stop];
        
        [self setState:IVWCanceling];
        
        if ([_delegate respondsToSelector:@selector(onEndOfSpeech)]) {
            [_delegate onEndOfSpeech];
        }
    }
    
    //结束引擎
    [_ivwEngine stopEngine];
    _ivwEngine.delegate = nil;
    _ivwEngine = nil;
    
    _queue = nil;
    
EXIT:
    
    [self setState:IVWEnd];
}

- (BOOL)startRecord {
    [IFlyDebugLog showLog:@"%s[IN]",__func__];
    
    // 确保启动新识别会话前，录音器已经结束
    for(int i = 0;i < 10;i++){
        if([_ivwRecorder isCompleted]){
            break;
        }
        [NSThread sleepForTimeInterval:0.005];
    }
    
    [IFlyDebugLog showLog:@"%s,recorder isCompleted=%d",__func__,[_ivwRecorder isCompleted]];
    if(![_ivwRecorder isCompleted]){
        return NO;
    }
    
    _ivwRecorder.delegate  = self;
    
    //初始化音频队列，设置音频队列的默认值
    [IFlyAudioSession initRecordingAudioSession];
    
    [_ivwRecorder setSample:_config.sampleRate]; //设置采样率
    [_ivwRecorder setPowerCycle:0.1]; //设置音量回调间隔
    
    //设置保存录音路径
    NSString *recPcmPath = @"ivw.pcm";
    //设置保存录音路径
    NSArray *appArray = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
    NSString *basePath = [appArray objectAtIndex:0];
    
    NSString *audioFullPath = [basePath stringByAppendingPathComponent:recPcmPath];
    [_ivwRecorder setSaveAudioPath:audioFullPath];
//    [_ivwRecorder setSaveAudioPath:@""];
    
    //启动录音
    if (![_ivwRecorder start]){
        _ivwRecorder.delegate  = nil;
        [IFlyDebugLog showLog:@"%s[OUT] recorder failed",__func__];
        return NO;
    }
    
    //当前状态为录音中
    [self setState:IVWRecording];
    
    [IFlyDebugLog showLog:@"%s[OUT]",__func__];
    
    return YES;
}

- (void)startIVW {
    [IFlyDebugLog showLog:@"%s[IN],self=%",__func__,self];
    
    int bRet = [_ivwEngine startEngine];
    if (bRet != 0){
        _error = bRet;
        [IFlyDebugLog showLog:@"%s, bRet=%d,self.isCancelled=%d",__func__,bRet,self.isCancelled];
    }
    
    [IFlyDebugLog showLog:@"%s[OUT],self=%d",__func__,self];
}

#pragma mark writeAudioData

- (void)writeAudioData {
    
    @synchronized(_queue){

        if ((_index < _audioCount) || (_index > _audioCount && _isInc)){
            NSData *audioData = [_queue objectForKey:[NSString stringWithFormat:@"%lu",(unsigned long)_index]];
            if (audioData){
                int err = 0;
                if (_index == 0) {
                    // begin
                    err = [_ivwEngine writeAudio:(const char*)([audioData bytes]) length: (unsigned int)[audioData length] audioStatus:0];
                } else {
                    err = [_ivwEngine writeAudio:(const char*)([audioData bytes]) length: (unsigned int)[audioData length] audioStatus:1];
                }
                
                //写入过程中发生错误
                if (err != 0){
                    _error = err;
                    _isNeedExit = YES;
                    
                    [IFlyDebugLog showLog:@"%s, error=%d",__func__,err];
                }
            }
            //释放已写入的音频内存
            [_queue removeObjectForKey:[NSString stringWithFormat:@"%lu",(unsigned long)_index]];
            
            if(_index == MAX_AUDIOQUEUE_COUNT_IVW-1){
                _index = 0;
                _isInc = NO;
            } else {
                _index++;
            }
        }
    }
}

- (void)writeEndData {
    //写入尾数据，告诉识别引擎数据已经写入完成，写入空数据时报错10008 $$$$$
//    [_ivwEngine writeAudio:(const char*)[[NSData data] bytes] length:0 audioStatus:2];
}

#pragma mark setIVWState

- (void)setState:(IVWState)state {
    
    if(state == _state){
        return;
    }

    @synchronized(self){
        _state = state;
    }
    
    switch (_state) {
        case IVWRecording:
        {
            if (_delegate && [_delegate respondsToSelector:@selector(onBeginOfSpeech)]){
                [_delegate onBeginOfSpeech];
            }
        }
            break;
        case IVWWakeuping:
        {
            if (_delegate && [_delegate respondsToSelector:@selector(onEndOfSpeech)]) {
                [_delegate onEndOfSpeech];
            }
        }
            break;
        case IVWCanceling:
            break;
        case IVWEnd:
        {
            [IFlyDebugLog showLog:@"%s[IVWEnd IN]",__func__];
            if (_delegate && [_delegate respondsToSelector:@selector(onCompletedWithErrorCode:)]){
                [_delegate onCompletedWithErrorCode:_error];
            }
            [IFlyDebugLog showLog:@"%s[IVWEnd OUT]",__func__];
        }
            break;
        default:
            break;
    }
}

#pragma mark - IFlyAudioRecorderDelegate

- (void)onIFlyRecorderBuffer:(const void *)buffer bufferSize:(int)size {
    @synchronized (self) {
        
        //最大保存0.15*100秒音频
        if(!(_index == (_audioCount+1) % MAX_AUDIOQUEUE_COUNT_IVW)){

            NSData *audioBuffer = [[NSData alloc] initWithBytes:buffer length:size];
            //将录音数据保存到缓冲区
            [_queue setValue:audioBuffer forKey:[NSString stringWithFormat:@"%lu",(unsigned long)_audioCount]];
            
            if(_audioCount == MAX_AUDIOQUEUE_COUNT_IVW-1){
                _audioCount = 0;
                _isInc = YES;
            }else{
                _audioCount++;
            }
            
        }
    }
}

- (void)onIFlyRecorderVolumeChanged:(int)volume {
//    [IFlyDebugLog showLog:@"volume:%i", volume];
    if (volume == -1){
        log(@"录音器错误！");
        if (_delegate && [_delegate respondsToSelector:@selector(onCompletedWithErrorCode:)]){
            [_delegate onCompletedWithErrorCode:20006];
        }
        return;
    }
    
    if (_delegate && [_delegate respondsToSelector:@selector(onVolumeChanged:)]){
        
        [_delegate onVolumeChanged:volume];
    }
}

- (void)onIFlyRecorderError:(IFlyAudioRecorder *)recorder errorCode:(NSUInteger)errorCode {
    _error = (int)errorCode;
}

#pragma mark - IFlyWakeupEngineDelegate

- (void)onWakeupEngineRunEndDelegate:(int)errorCode {
    [IFlyDebugLog showLog:@"%s,eror=%d",__func__,errorCode];
    
    if(0 != errorCode){
        _error = errorCode;
    }
    
    //需要退出线程
    _isNeedExit = YES;
}

- (BOOL)onWakeupEngineStopAndWaitResultDelegate {
    [IFlyDebugLog showLog:@"%s,self.state=%d",__func__,self.state];
    
    if (self.state == IVWRecording) {
        //停止录音
        [_ivwRecorder stop];
        
        //写入尾数据
        [self writeEndData];
        
        //等待识别结果
        [self setState:IVWWakeuping];
    }
    
    return YES;
}

- (void)onWakeupEngineGetResultDelegate:(NSString *)result {
    [IFlyDebugLog showLog:@"%s,self.state=%d",__func__,self.state];
    
    if(_delegate && [_delegate respondsToSelector:@selector(onResultStr:)]) {
        [_delegate onResultStr:result];
    }
}

- (void)onWakeupEngineOnEvent:(int)eventType isLast:(BOOL)isLast arg1:(int)arg1 data:(NSString *)eventData {
    // event pass
}


@end
